

#include "img_overlay.h"

#include "interop_private.h"

namespace
{
//
// This the static data for a 8x8 bit mapped font used by the overlay functions.
//
static const unsigned char g_font_data [256][8] = {
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e},
    {0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e},
    {0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00},
    {0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00},
    {0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c},
    {0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c},
    {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00},
    {0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff},
    {0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00},
    {0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff},
    {0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78},
    {0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18},
    {0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0},
    {0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0},
    {0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99},
    {0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00},
    {0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00},
    {0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18},
    {0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00},
    {0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00},
    {0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78},
    {0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00},
    {0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff},
    {0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00},
    {0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00},
    {0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00},
    {0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00},
    {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00},
    {0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00},
    {0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00},
    {0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00},
    {0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00},
    {0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00},
    {0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00},
    {0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00},
    {0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00},
    {0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00},
    {0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00},
    {0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60},
    {0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00},
    {0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00},
    {0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00},
    {0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00},
    {0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00},
    {0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00},
    {0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00},
    {0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00},
    {0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00},
    {0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00},
    {0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00},
    {0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00},
    {0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00},
    {0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60},
    {0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00},
    {0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00},
    {0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00},
    {0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00},
    {0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00},
    {0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00},
    {0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00},
    {0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00},
    {0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00},
    {0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00},
    {0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00},
    {0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00},
    {0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00},
    {0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},
    {0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00},
    {0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00},
    {0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00},
    {0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00},
    {0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00},
    {0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00},
    {0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00},
    {0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00},
    {0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00},
    {0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00},
    {0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},
    {0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00},
    {0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00},
    {0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00},
    {0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00},
    {0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00},
    {0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00},
    {0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00},
    {0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00},
    {0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00},
    {0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff},
    {0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00},
    {0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00},
    {0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00},
    {0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00},
    {0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},
    {0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00},
    {0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8},
    {0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00},
    {0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},
    {0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78},
    {0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00},
    {0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},
    {0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00},
    {0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00},
    {0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00},
    {0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0},
    {0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e},
    {0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00},
    {0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00},
    {0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00},
    {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00},
    {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00},
    {0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00},
    {0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00},
    {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8},
    {0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00},
    {0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00},
    {0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00},
    {0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00},
    {0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00},
    {0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78},
    {0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},
    {0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},
    {0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00},
    {0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},
    {0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},
    {0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},
    {0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38},
    {0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00},
    {0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},
    {0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},
    {0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},
    {0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00},
    {0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},
    {0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00},
    {0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00},
    {0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00},
    {0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00},
    {0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00},
    {0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},
    {0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},
    {0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},
    {0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},
    {0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},
    {0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8},
    {0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00},
    {0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00},
    {0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18},
    {0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00},
    {0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30},
    {0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7},
    {0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70},
    {0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},
    {0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},
    {0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},
    {0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},
    {0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00},
    {0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00},
    {0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00},
    {0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00},
    {0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00},
    {0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00},
    {0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f},
    {0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03},
    {0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00},
    {0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00},
    {0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00},
    {0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88},
    {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa},
    {0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee},
    {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
    {0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18},
    {0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18},
    {0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36},
    {0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36},
    {0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18},
    {0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36},
    {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36},
    {0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36},
    {0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00},
    {0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00},
    {0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18},
    {0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00},
    {0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18},
    {0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18},
    {0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00},
    {0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18},
    {0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18},
    {0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36},
    {0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36},
    {0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36},
    {0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36},
    {0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00},
    {0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36},
    {0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00},
    {0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18},
    {0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36},
    {0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00},
    {0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18},
    {0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36},
    {0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36},
    {0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18},
    {0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18},
    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
    {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff},
    {0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0},
    {0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f},
    {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00},
    {0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0},
    {0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00},
    {0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00},
    {0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00},
    {0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00},
    {0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0},
    {0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00},
    {0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc},
    {0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00},
    {0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00},
    {0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00},
    {0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00},
    {0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0},
    {0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00},
    {0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00},
    {0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00},
    {0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00},
    {0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00},
    {0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00},
    {0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18},
    {0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70},
    {0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00},
    {0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00},
    {0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00},
    {0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c},
    {0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00},
    {0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};

using namespace img::pixel_type;
using img_lib::overlay::rgba;

constexpr inline bool is_transparent( BGRA32 clr ) noexcept     { return clr.a == 0; }
constexpr inline bool is_transparent( Y8A8 clr ) noexcept       { return clr.a == 0; }
constexpr inline bool is_transparent( Y8U8V8A8 clr ) noexcept   { return clr.a == 0; }

constexpr inline BGRA32     translate_clr_to_rgb( rgba src ) noexcept
{
    return BGRA32{ src.b, src.g, src.r, src.a };
}
constexpr inline Y8A8       translate_clr_to_y( rgba src ) noexcept
{
    float res = (0.299f * src.r) + (0.587f * src.g) + (0.114f * src.b);
    return Y8A8{ (uint8_t)(res > 255.f ? 255 : res), src.a };
}

constexpr inline Y8U8V8A8   translate_clr_to_yuv( rgba src ) noexcept
{
    int yt = (int)(256 * 0.299f) * src.r + (int)(256 * 0.587f) * src.g + (int)(256 * 0.114f) * src.b;
    int ut = (int)(256 * -0.173f) * src.r - (int)(256 * 0.339f) * src.g + (int)(256 * 0.512f) * src.b + 128 * 256;
    int vt = (int)(256 * 0.512f) * src.r - (int)(256 * 0.427f) * src.g - (int)(256 * 0.084f) * src.b + 128 * 256;

    yt >>= 8;
    ut >>= 8;
    vt >>= 8;

    return Y8U8V8A8{
        (uint8_t)CLIP( yt, 0, 0xFF ),
        (uint8_t)CLIP( ut, 0, 0xFF ),
        (uint8_t)CLIP( vt, 0, 0xFF ),
        src.a
    };
}

template<img::fourcc Tfcc>
constexpr auto    calc_color_for_type( rgba clr )
{
    if constexpr( 
        Tfcc == img::fourcc::BGRA32 ||
        Tfcc == img::fourcc::BGR24 ||
        Tfcc == img::fourcc::BGRA64
        )
    {
        return translate_clr_to_rgb( clr );
    }
    else if constexpr( 
        Tfcc == img::fourcc::MONO8 || 
        Tfcc == img::fourcc::MONO16 ||
        Tfcc == img::fourcc::MONO10 ||
        Tfcc == img::fourcc::MONO10_SPACKED ||
        Tfcc == img::fourcc::MONO10_MIPI_PACKED ||
        Tfcc == img::fourcc::MONO12 ||
        Tfcc == img::fourcc::MONO12_PACKED ||
        Tfcc == img::fourcc::MONO12_SPACKED ||
        Tfcc == img::fourcc::MONO12_MIPI_PACKED
        )
    {
        return translate_clr_to_y( clr );
    }
    else if constexpr( 
        Tfcc == img::fourcc::UYVY ||
        Tfcc == img::fourcc::YUY2 ||
        Tfcc == img::fourcc::Y411
        )
    {
        return translate_clr_to_yuv( clr );
    }
    else
    {
        return translate_clr_to_rgb( clr );
    }
}

FORCEINLINE void    write_pix_to_iter( BGRA32* base, int index, BGRA32 clr ) noexcept
{
    base[index] = clr;
}
FORCEINLINE void    write_pix_to_iter( BGR24* base, int index, BGRA32 clr ) noexcept
{
    base[index] = BGR24{ clr.g, clr.b, clr.r };
}
FORCEINLINE void    write_pix_to_iter( BGRA64* base, int index, BGRA32 clr ) noexcept
{
    base[index] = BGRA64{ uint16_t( clr.b << 8 ), uint16_t( clr.g << 8 ), uint16_t( clr.r << 8 ), 0xFFFF };
}
FORCEINLINE void    write_pix_to_iter( Y8* base, int index, Y8A8 clr ) noexcept
{
    base[index] = Y8{ clr.y };
}
FORCEINLINE void    write_pix_to_iter( Y16* base, int index, Y8A8 clr ) noexcept
{
    base[index] = Y16{ uint16_t( clr.y << 8 ) };
}

FORCEINLINE void    write_pix_to_iter( UYVY* base, int index, Y8U8V8A8 clr ) noexcept
{
    auto& item = base[index / 2];
    switch( index % 2 )
    {
    case 0: item.y0 = clr.y; break;
    case 1: item.y1 = clr.y; break;
    };
    item.u = clr.u;
    item.v = clr.v;
}

FORCEINLINE void    write_pix_to_iter( YUY2* base, int index, Y8U8V8A8 clr ) noexcept
{
    auto& item = base[index / 2];
    switch( index % 2 )
    {
    case 0: item.y0 = clr.y; break;
    case 1: item.y1 = clr.y; break;
    };
    item.u = clr.u;
    item.v = clr.v;
}

FORCEINLINE void    write_pix_to_iter( Y411* base, int index, Y8U8V8A8 clr ) noexcept
{
    auto& item = base[index / 4];
    switch( index % 4 ) {
    case 0: item.y0 = clr.y; break;
    case 1: item.y1 = clr.y; break;
    case 2: item.y2 = clr.y; break;
    case 3: item.y3 = clr.y; break;
    };
    item.u = clr.u;
    item.v = clr.v;
}


FORCEINLINE void    write_pix_to_iter( RAW10_MIPI_PACKED* base, int index, Y8A8 clr ) noexcept
{
    auto& item = base[index / 4];
    switch( index % 4 )
    {
    case 0: item.v0 = clr.y; item.v4 &= 0b11111100; break;
    case 1: item.v1 = clr.y; item.v4 &= 0b11110011; break;
    case 2: item.v2 = clr.y; item.v4 &= 0b11001111; break;
    case 3: item.v3 = clr.y; item.v4 &= 0b00111111; break;
    };
}

FORCEINLINE void    write_pix_to_iter( RAW10* base, int index, Y8A8 clr ) noexcept
{
    base[index].v0 = clr.y << 2;    // 8 -> 10 bit
}

//FORCEINLINE void    write_pix_to_iter( RAW10_SPACKED* base, int index, Y8A8 clr ) noexcept
//{
//    uint64_t data_u64 = 0;
//    memcpy( &data_u64, base + index / 4, sizeof( RAW10_SPACKED ) );
//    
//    int offset = index % 4;
//    uint64_t y10_Val = clr.y << 2;
//    data_u64 &= ~(0x3FFull << (offset * 10));
//    data_u64 |= y10_Val << (offset * 10);
//    mempcpy( base + index / 4, &data_u64, sizeof( RAW10_SPACKED ) );
//}

FORCEINLINE void    write_pix_to_iter( RAW12* base, int index, Y8A8 clr ) noexcept
{
    base[index].v0 = clr.y << 4;    // 8 -> 12 bit
}

FORCEINLINE void    write_pix_to_iter( RAW12_MIPI_PACKED* base, int index, Y8A8 clr ) noexcept
{
    auto& item = base[index / 2];
    switch( index % 2 )
    {
    case 0: item.v0 = clr.y; break;
    case 1: item.v1 = clr.y; break;
    };
    item.v2 = 0;
}


template<img::fourcc Tfcc>
struct planar_iter
{
    planar_iter( const img::img_descriptor& d, int pos_y )
    {
        p_line_start_ = img::get_line_start( d, pos_y );
    }
    void    write( int pos_x, Y8U8V8A8 clr )
    {
        //assign_clr<Tfcc>( plane_pitch_, p_line_start_, pos_x, clr );
    }
private:
    uint8_t*    p_line_start_;
};

template<img::fourcc Tfcc>
auto make_line_iter( const img::img_descriptor& d, int pos_y )
{
    if constexpr( Tfcc == img::fourcc::BGRA32 )       { return img::get_line_start<BGRA32>( d, pos_y ); }
    else if constexpr( Tfcc == img::fourcc::BGR24 )   { return img::get_line_start<BGR24>( d, pos_y ); }
    else if constexpr( Tfcc == img::fourcc::BGRA64 )  { return img::get_line_start<BGRA64>( d, pos_y ); }
    else if constexpr( Tfcc == img::fourcc::MONO8 )   { return img::get_line_start<Y8>( d, pos_y ); }
    else if constexpr( Tfcc == img::fourcc::MONO16 )  { return img::get_line_start<Y16>( d, pos_y ); }
    else if constexpr( Tfcc == img::fourcc::RAW8 )    { return img::get_line_start<Y8>( d, pos_y ); }
    else if constexpr( Tfcc == img::fourcc::RAW16 )   { return img::get_line_start<Y16>( d, pos_y ); }
    else if constexpr( Tfcc == img::fourcc::UYVY )    { return img::get_line_start<UYVY>( d, pos_y ); }
    else if constexpr( Tfcc == img::fourcc::YUY2 )    { return img::get_line_start<YUY2>( d, pos_y ); }
    else if constexpr( Tfcc == img::fourcc::Y411 )    { return img::get_line_start<Y411>( d, pos_y ); }

    else if constexpr( Tfcc == img::fourcc::MONO10 ) { return img::get_line_start<RAW10>( d, pos_y ); }
    else if constexpr( Tfcc == img::fourcc::MONO10_MIPI_PACKED ) { return img::get_line_start<RAW10_MIPI_PACKED>( d, pos_y ); }
    //else if constexpr( Tfcc == img::fourcc::MONO10_SPACKED )      { return img::get_line_start<RAW10_SPACKED>( d, pos_y ); }
    else if constexpr( Tfcc == img::fourcc::MONO12 ) { return img::get_line_start<RAW12>( d, pos_y ); }
    else if constexpr( Tfcc == img::fourcc::MONO12_MIPI_PACKED ) { return img::get_line_start<RAW12_MIPI_PACKED>( d, pos_y ); }
    //else if constexpr( Tfcc == img::fourcc::MONO12_PACKED )      { return img::get_line_start<RAW12_PACKED>( d, pos_y ); }
    //else if constexpr( Tfcc == img::fourcc::MONO12_SPACKED )     { return img::get_line_start<RAW12_SPACKED>( d, pos_y ); }
    else
    {
        static_assert(Tfcc == img::fourcc::BGRA32, "Failed to match Tfcc to a iterator type");
        return planar_iter<Tfcc>( d, pos_y );
    }
}


template<img::fourcc fcc, class Tclr>
FORCEINLINE void    write_pix_to_iter( planar_iter<fcc>& iter, int pos, Tclr clr )
{
    iter.write( pos, clr );
}

template<class TIter,class Tclr>
FORCEINLINE void    write_line( TIter iter, const int start_x, const int count, Tclr clr )
{
    if( is_transparent( clr ) ) {
        return;
    }
    for( int x = 0; x < count; x++ ) {
        write_pix_to_iter( iter, x + start_x, clr );
    }
}

template<class Titer, class Tclr>
FORCEINLINE void    write_pix_to_iter_test( Titer iter, int pos, Tclr clr )
{
    if( !is_transparent( clr ) ) {
        write_pix_to_iter( iter, pos, clr );
    }
}

template<class TIter, class Tclr>
void    write_text_line( TIter iter, const int start_x, const int dim_x, const Tclr fg_color, const Tclr bg_color, const char* text, const size_t text_len, const int row, const int scaling )
{
    int pos_x = start_x;
    write_pix_to_iter_test( iter, pos_x, bg_color );    // first | in background color for text line
    if( ++pos_x == dim_x ) {
        return;
    }

    // Generate a row of the overlay.
    // 
    for( const char* cur_char = text; cur_char < (text + text_len); ++cur_char )
    {
        const uint8_t letter = (uint8_t)(*cur_char);
        const uint8_t char_mask = g_font_data[letter][row];
        for( unsigned int mask = 0x80; mask; mask >>= 1 )
        {
            for( int scalerX = 0; scalerX < scaling; ++scalerX )
            {
                // depending on mask write foreground or background color
                if( char_mask & mask ) {
                    write_pix_to_iter_test( iter, pos_x, fg_color );
                } else {
                    write_pix_to_iter_test( iter, pos_x, bg_color );
                }
                if( ++pos_x == dim_x ) {
                    return;
                }
            }
        }

        // 
        // Separate each character by one space. Account for the border
        // space at the end by placing the separator after the last 
        // character also.
        //
        write_pix_to_iter_test( iter, pos_x, bg_color );
        if( ++pos_x == dim_x ) {
            return;
        }
    }
}


template<img::fourcc Tfcc>
void	render_worker( const img::img_descriptor& data, const img::point start_pos, const int scaling, const char* text, const size_t text_len,
    rgba in_background_color, rgba in_foreground_color, const int pixel_per_line_to_write )
{
    const auto foreground_color = calc_color_for_type<Tfcc>( in_foreground_color );
    const auto background_color = calc_color_for_type<Tfcc>( in_background_color );

    int cursor_y = start_pos.y;

    //
    // Write the first row in background color.
    write_line( make_line_iter<Tfcc>( data, cursor_y ), start_pos.x, pixel_per_line_to_write, background_color );
    if( ++cursor_y == data.dim.cy ) {
        return;
    }

    for( int row = 0; row < 8; row++ )  // this loops over the 8 rows a text lines contains
    {
        for( int scalerY = 0; scalerY < scaling; ++scalerY )    // this loops over the scaling factor
        {
            // write the text line
            write_text_line( make_line_iter<Tfcc>( data, cursor_y ), start_pos.x, data.dim.cx, foreground_color, background_color, text, text_len, row, scaling );

            if( ++cursor_y == data.dim.cy ) { // reached dim_y, so quit
                return;
            }
        }
    }

    //  
    // Add the bottom section of the overlay line
    //
    if( cursor_y < data.dim.cy )
    {
        write_line( make_line_iter<Tfcc>( data, cursor_y ), start_pos.x, pixel_per_line_to_write, background_color );
    }
}

}

void	img_lib::overlay::render_text( const img::img_descriptor& data, img::point pos, int scaling, const char* pText, size_t text_len, rgba FgColor, rgba BgColor )
{
    if( text_len == 0 || pText == nullptr )     return; // text len == 0, skip fully
    if( scaling <= 0 )                          return; // scaling invalid

    // When pos is outside of the image, skip
    if( pos.x >= data.dim.cx )	return;
    if( pos.y >= data.dim.cy )	return;


    // The overlay is drawn in the form of 
    //
    // ---------
    // |a|a|a|a|
    // ---------
    //
    // - rows are 1 pixel high
    // a rows are 8 (*s caling) pixel thick
    // | columns are 1 pixel thick
    // a columns are 8 (* scaling) pixel thick
    //
    // this calculates the exact dimensions needed
    int text_width_in_pixel = (int)text_len * scaling * 8 + 1 + (int)text_len;
    int text_height_in_pixel = 2 + scaling * 8; // 1 row over/under lines + 8 * scaling rows

    //
    // Adjust for center overlays.
    //
    // NOTE: If the overlay doesn't fit into the synthesis buffer, this
    // merely left aligns the overlay and clips off the right side.
    //
    if( pos.x == POSITION_CENTER ) 
    {
        if( text_width_in_pixel >= data.dim.cx ) {
            pos.x = 0;
        } else {
            pos.x = (data.dim.cx - text_width_in_pixel) / 2;
        }
    }
    if( pos.y == POSITION_CENTER )
    {
        if( text_height_in_pixel >= data.dim.cy ) {
            pos.y = 0;
        } else {
            pos.y = (data.dim.cy - text_height_in_pixel) / 2;
        }
    }

    assert( pos.x < data.dim.cx );
    assert( pos.y < data.dim.cy );

    if( text_width_in_pixel > (data.dim.cx - pos.x) ) // when the text is longer then the available space, we clip at dim_x
    {
        text_width_in_pixel = data.dim.cx - pos.x;
    }

    bool bFlip = img::is_bottom_up_fcc( data.fourcc_type() );

    img::img_descriptor cur_img = bFlip ? img::flip_image_in_img_desc( data ) : data;

    switch( data.fourcc_type() )
    {
    case img::fourcc::BGRA32:       render_worker<img::fourcc::BGRA32>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel ); return;
    case img::fourcc::BGRA64:       render_worker<img::fourcc::BGRA64>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel ); return;
    case img::fourcc::BGR24:        render_worker<img::fourcc::BGR24>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel ); return;
    case img::fourcc::MONO8:        render_worker<img::fourcc::MONO8>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel ); return;
    case img::fourcc::MONO16:       render_worker<img::fourcc::MONO16>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel ); return;
    case img::fourcc::YUV8PLANAR:   render_worker<img::fourcc::MONO8>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel ); return;
    case img::fourcc::YUV16PLANAR:  render_worker<img::fourcc::MONO16>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel ); return;

    case img::fourcc::YV12:
    case img::fourcc::I420:
    case img::fourcc::NV12:
        render_worker<img::fourcc::MONO8>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel );
        return;

    case img::fourcc::MONO10:
    case img::fourcc::BGGR10:
    case img::fourcc::GRBG10:
    case img::fourcc::RGGB10:
    case img::fourcc::GBRG10:
        render_worker<img::fourcc::MONO10>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel );
        return;

    case img::fourcc::MONO10_MIPI_PACKED:
    case img::fourcc::BGGR10_MIPI_PACKED:
    case img::fourcc::GRBG10_MIPI_PACKED:
    case img::fourcc::RGGB10_MIPI_PACKED:
    case img::fourcc::GBRG10_MIPI_PACKED:
        render_worker<img::fourcc::MONO10_MIPI_PACKED>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel );
        return;

    //case img::fourcc::MONO10_SPACKED:
    //case img::fourcc::BGGR10_SPACKED:
    //case img::fourcc::GRBG10_SPACKED:
    //case img::fourcc::RGGB10_SPACKED:
    //case img::fourcc::GBRG10_SPACKED:
    //    render_worker<img::fourcc::MONO10_SPACKED>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel );
    //    return;

    case img::fourcc::MONO12:
    case img::fourcc::BGGR12:
    case img::fourcc::GRBG12:
    case img::fourcc::RGGB12:
    case img::fourcc::GBRG12:
        render_worker<img::fourcc::MONO12>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel );
        return;

    case img::fourcc::MONO12_MIPI_PACKED:
    case img::fourcc::BGGR12_MIPI_PACKED:
    case img::fourcc::GRBG12_MIPI_PACKED:
    case img::fourcc::RGGB12_MIPI_PACKED:
    case img::fourcc::GBRG12_MIPI_PACKED:
        render_worker<img::fourcc::MONO12_MIPI_PACKED>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel );
        return;

    //case img::fourcc::MONO12_PACKED:
    //case img::fourcc::BGGR12_PACKED:
    //case img::fourcc::GRBG12_PACKED:
    //case img::fourcc::RGGB12_PACKED:
    //case img::fourcc::GBRG12_PACKED:
    //    render_worker<img::fourcc::MONO12>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel );
    //    return;

    //case img::fourcc::MONO12_SPACKED:
    //case img::fourcc::BGGR12_SPACKED:
    //case img::fourcc::GRBG12_SPACKED:
    //case img::fourcc::RGGB12_SPACKED:
    //case img::fourcc::GBRG12_SPACKED:
    //    render_worker<img::fourcc::MONO12_SPACKED>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel );
    //    return;

    case img::fourcc::IYU1:
    case img::fourcc::Y411:
        render_worker<img::fourcc::Y411>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel );
        return;

    case img::fourcc::UYVY:
        render_worker<img::fourcc::UYVY>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel );
        return;
    case img::fourcc::YUY2:
        render_worker<img::fourcc::YUY2>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel );
        return;

    case img::fourcc::BGGR8:
    case img::fourcc::GBRG8:
    case img::fourcc::RGGB8:
    case img::fourcc::GRBG8:
        render_worker<img::fourcc::MONO8>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel );
        return;

    case img::fourcc::BGGR16:
    case img::fourcc::GBRG16:
    case img::fourcc::RGGB16:
    case img::fourcc::GRBG16:
        render_worker<img::fourcc::MONO16>( cur_img, pos, scaling, pText, text_len, BgColor, FgColor, text_width_in_pixel );
        return;

    default:
        break;
    }
}
